The goal is to find a way to make a layer of silver transparent enough to see the difference with a normal layer. We imagined to way to perform such a goal : first, using chemical vapor deposition we could make a layer of silver thick enough to transmit light (around 50nm thick). This consists in a stack of thick films, a stack that can be modeled using kubelka-munk theory. Another way could be to drill several holes in the layer to let light pass through. This needs a pattern to be performed, and this pattern can lead to Moiré or to pattern recognition problems. So we must find a pattern which avoid these.
First we should understand the behavior of one layer of silver, according to its thickness. Then we will be able to compute the Kubelka-Munk model. So in this part, we compute the spectral transmissivity of a layer of silver according to its thickness.
from numpy import *
import numpy as np
import matplotlib.pyplot as plt
We use the spectral refractive indices and extinction coefficients provided by Mathieu Hebert to compute the spectral reflectivity and transmissivity thanks to the formula provided in "Principle of Optics, Max Born & Emil Wolf".
#propagation medium (air)
n1=1
#substrat (glass)
n3=1.5
#Metal (Ag)
n2 = []
k2 = []
l = []
h = 30e-9 #metal thickness
with open("AgIndicesHebert.txt") as file:
for line in file:
var = line.split("\t")
l.append(var[0])
k2.append(var[1])
n2.append(var[2])
#careful with BOM of UTF file
l = [float(x) for x in l]
n2 = [float(x) for x in n2]
k2 = [float(x) for x in k2]
Reflectance = []
Transmittance = []
for i in range(len(l)):
R = ((n1-n2[i])**2+k2[i]**2)/((n1+n2[i])**2+k2[i]**2)
T = n3*16*(n2[i]**2+k2[i]**2)/(((n3+n2[i]**2)**2+k2[i]**2)**2)*e**(-8*pi*k2[i]**2*h/(l[i]*1e-3))
Reflectance.append(R)
Transmittance.append(T)
fig, ax = plt.subplots()
ax.plot(l, Reflectance, color='blue', label='Reflectance')
ax.plot(l, Transmittance, color='orange', label='Transmittance')
ax.set_title("Silver")
ax.set_xlabel("wavelength")
ax.legend()
<matplotlib.legend.Legend at 0x7f433f348290>
We then define 2 functions which depends on the thickness h of the layer.
def reflectivity(l,h):
Reflectance = []
for i in range(len(l)):
R = ((n1-n2[i])**2+k2[i]**2)/((n1+n2[i])**2+k2[i]**2)
Reflectance.append(R)
return Reflectance
def transmittivity(l,h):
Transmittance = []
for i in range(len(l)):
T = n3*16*(n2[i]**2+k2[i]**2)/(((n3+n2[i]**2)**2+k2[i]**2)**2)*e**(-8*pi*k2[i]**2*h/(l[i]*1e-9))
Transmittance.append(T)
return Transmittance
thickness = [1e-9, 1e-8, 1e-7, 1e-6, 1e-5, 1e-4, 1e-3]
RH = []
TH = []
for h in thickness:
RH.append(reflectivity(l,h))
TH.append(transmittivity(l,h))
import plotly.graph_objects as go
fig = go.Figure()
# Add traces
i=0
for h in thickness:
fig.add_trace(go.Scatter(x=l, y=TH[i],
mode='lines',
name=h))
i+=1
annotations = []
# Title
annotations.append(dict(xref='paper', yref='paper', x=0.0, y=1.05,
xanchor='left', yanchor='bottom',
text='Transmissivity of Ag film as a function of thickness',
font=dict(family='Arial',
size=30,
color='rgb(37,37,37)'),
showarrow=False))
# Source
annotations.append(dict(xref='paper', yref='paper', x=0.5, y=-0.1,
xanchor='center', yanchor='top',
text='Source: Principles of Optics 7th Max Born & Emil Wolf ',
font=dict(family='Arial',
size=12,
color='rgb(150,150,150)'),
showarrow=False))
fig.update_layout(annotations=annotations)
fig.show()
Thanks to this figure, we understand that we need a thickness of multiples of 10 nanometers.
We need to define a grid of holes to drill. For that, we try to model a blue noise, a specific noise which is homogeneous and quasi-random. We use the R sequence mathematical theory to build the grid.
def phi(d):
x=2.0000
for i in range(10):
x = pow(1+x,1/(d+1))
return x
def Rseq(d,n):
g = phi(d)
a1 = 1.0/g
a2 = 1.0/(g*g)
X, Y = [],[]
for i in range(1,n):
X.append((0.5+a1*i) %1)
Y.append((0.5+a2*i) %1)
return X,Y
import matplotlib.pyplot as plt
# Number of dimensions.
d=2
# number of required points
n=10000
X,Y = Rseq(d,n)
plt.scatter(X,Y, s=0.5, c='black')
<matplotlib.collections.PathCollection at 0x7f433f366690>
Thanks to this first image, we see that the pattern seems to be periodic. We need to know if Moiré patterns are visible.
#Image de taille 256x256 avec 26384 trous de 1 pixel.
# Number of dimensions.
d=2
# number of required points
n=10000
X,Y = Rseq(d,n)
X = [int(floor(x*256)) for x in X]
Y = [int(floor(y*256)) for y in Y]
M = np.ones([256,256], dtype=int)
i = 0
for x in X:
y = Y[i]
M[x][y] = 0
i+=1
plt.imshow(M, cmap='gray')
<matplotlib.image.AxesImage at 0x7f4336be3550>
To do that, we will shift the original image left to pretend we watch the two overlaying layers with a non-zero angle from the normal. https://medium.com/analytics-vidhya/image-shifting-using-numpy-from-scratch-8bd52663da52
import numpy as np
# import cv2 Il y a un pb d'installation
import json
from matplotlib import pyplot as plt
import random
mat = np.matrix(M)
plt.axis("off")
plt.imshow(mat, cmap='gray')
plt.show()
# Pour les calculs
mat = abs(M-1)
def pad_vector(vector, how, depth, constant_value=0):
vect_shape = vector.shape[:2]
if (how == 'upper') or (how == 'top'):
pp = np.full(shape=(depth, vect_shape[1]), fill_value=constant_value)
pv = np.vstack(tup=(pp, vector))
elif (how == 'lower') or (how == 'bottom'):
pp = np.full(shape=(depth, vect_shape[1]), fill_value=constant_value)
pv = np.vstack(tup=(vector, pp))
elif (how == 'left'):
pp = np.full(shape=(vect_shape[0], depth), fill_value=constant_value)
#np.delete(vector, 255, 1)
pv = np.hstack(tup=(pp, vector))
elif (how == 'right'):
pp = np.full(shape=(vect_shape[0], depth), fill_value=constant_value)
pv = np.hstack(tup=(vector, pp))
else:
return vector
return pv
pmat = pad_vector(vector=mat, how='left', depth=3)
pmat = np.delete(pmat, [256 + i for i in range(3)], 1)
plt.axis("off")
plt.imshow(pmat, cmap='gray')
plt.show()
By multiplying the two boolean matrices term to term, we will know that Moiré patterns are visible if it produces lines or periodic patterns on the residual image.
T = mat*pmat
plt.axis("off")
plt.imshow(T, cmap='gray')
plt.show()
T = abs(T-1)
plt.axis("off")
plt.imshow(T, cmap='gray')
plt.show()
This is the case here, so we need to find another R sequence to build the drilling grid.